﻿using SIE.SCADA.Common;
using SIE.SCADA.Common.Helper;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using SIE.SCADA.Common.Log;
using SIE.SCADA.Helper;

namespace SIE.SCADA.StationDemo.Cache
{
    /// <summary>
    /// 缓存客户端
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CacheClient<T> : IDisposable
    {

        private DateTime _lastTime = DateTime.MinValue;
        internal CacheConfig CacheConfig { get; set; }

        private string FilePath { get; set; }

        // 每隔30秒去删除一下超过缓存时间的文件
        private Timer _timerClose;
        //接收客户端发送消息的线程
        protected AdvancedThread ThreadSend { get; set; }

        internal BlockingCollection<T> SaveCollection { get; set; }

        internal bool IsStarted { get; private set; }

        public CacheClient(CacheConfig cacheConfig, string fileName)
        {
            CacheConfig = cacheConfig;
            CacheConfig.FileName = fileName;
            try
            {
                if (CacheConfig.FileName != null)
                {
                    FilePath = GetDirFullName(CacheConfig.CacheFilePath, CacheConfig.FileName);
                }
                if (FilePath != null && !Directory.Exists(FilePath)) Directory.CreateDirectory(FilePath);

            }
            catch (Exception ex)
            {
                Logger.WarnException(ex);
            }
            _timerClose = new Timer(new TimerCallback(DeleteCacheFile), this, 5000, 30000);
        }

        private string GetDirFullName(string containerName, string dirName)
        {
            Check.NotNull(containerName, nameof(containerName));
            Check.NotNull(dirName, nameof(dirName));

            containerName = containerName.Replace("\\", Path.DirectorySeparatorChar.ToString())
                    .Replace("/", Path.DirectorySeparatorChar.ToString());
            dirName = dirName.Replace("\\", Path.DirectorySeparatorChar.ToString())
                    .Replace("/", Path.DirectorySeparatorChar.ToString());
            var project = ServerHostManager.GetServerHost().Project;
            if (project == null || Path.IsPathRooted(containerName))
            {
                return Path.Combine(containerName, dirName);
            }
            var projectDir = project.ProjectDir.Replace("\\", Path.DirectorySeparatorChar.ToString())
                    .Replace("/", Path.DirectorySeparatorChar.ToString());
            return Path.Combine(projectDir, containerName, dirName);
        }

        public void Start()
        {
            try
            {
                if (IsStarted) return;
                SaveCollection = new BlockingCollection<T>();
                IsStarted = true;
                //创建线程
                ThreadSend = new AdvancedThread(Cache, 0);
                ThreadSend.Start();
            }
            catch (Exception ex)
            {
                Logger.Warn(ex.Message);
                Logger.Warn(ex.StackTrace);
            }
        }

        private void Cache()
        {
            try
            {
                if (SaveCollection.TryTake(out T msg))
                {
                    SaveCache(msg);
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
            catch (Exception ex)
            {
                Logger.Warn(ex.Message);
                Logger.Warn(ex.StackTrace);
            }
        }

        public void Stop()
        {
            try
            {
                IsStarted = false;
                ThreadSend?.Stop();
                ThreadSend = null;
                Dispose();
                SaveCollection?.Dispose();
            }
            catch (Exception ex)
            {
                Logger.WarnException(ex);
                IsStarted = false;
            }
        }

        /// <summary>
        /// 添加到集合
        /// </summary>
        /// <param name="t"></param>
        public void Add(T t)
        {
            SaveCollection.Add(t);
        }

        public void Add(IEnumerable<T> msgs)
        {
            foreach (var msg in msgs)
            {
                Add(msg);
            }
        }

        /// <summary>
        /// 保存缓存到文件中
        /// </summary>
        private void SaveCache(T msg)
        {
            if (string.IsNullOrEmpty(FilePath)) return;
            try
            {
                var path = Path.Combine(FilePath,"Faild" +  ".cach");
                var str = JsonHelper.JsonSerialize(msg);
                str = str.Replace(Environment.NewLine, "") + Environment.NewLine;
                File.AppendAllText(path, str);
            }
            catch (Exception ex)
            {
                Logger.WarnException(ex);
            }
        }

        /// <summary>
        /// 删除超出缓存时间的文件
        /// </summary>
        private void DeleteCacheFile(object obj)
        {
            if (string.IsNullOrEmpty(FilePath) || !Directory.Exists(FilePath)) return;
            var paths = Directory.GetFiles(FilePath, "*.smsg");
            DateTime now = DateTime.Now;
            foreach (var path in paths)
            {
                try
                {
                    var name = Path.GetFileNameWithoutExtension(path);
                    var time = DateTime.ParseExact(name, "yyyyMMddHHmm", CultureInfo.InvariantCulture);
                }
                catch (Exception ex)
                {
                    Logger.WarnException(ex);
                }
            }
        }

        /// <summary>
        /// 把缓存文件加载上来
        /// </summary>
        /// <returns></returns>
        public List<T> LoadCacheFiles()
        {
            if (string.IsNullOrEmpty(FilePath) || !Directory.Exists(FilePath)) return null;
            DateTime now = DateTime.Now;
            var list = new List<T>();
            var paths = Directory.GetFiles(FilePath, "*.cach");
            foreach (var path in paths)
            {
                try
                {
                    var lines = File.ReadAllLines(path, Encoding.UTF8);
                    foreach (var line in lines)
                    {
                        try
                        {
                            var msg = JsonHelper.JsonDeserialize<T>(line);
                            if (msg != null)
                            {
                                list.Add(msg);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Trace(ex.Message);
                        }
                    }
                    File.Delete(path);
                }
                catch (Exception ex)
                {
                    Logger.WarnException(ex);
                }
            }
            return list;
        }

        public List<T> GetCacheFile(out string filePath)
        {
            filePath = string.Empty;
            if (string.IsNullOrEmpty(FilePath) || !Directory.Exists(FilePath)) return null;
            DateTime now = DateTime.Now;
            var list = new List<T>();
            var paths = Directory.GetFiles(FilePath, "*.cach");
            if (paths.Length > 0)
            {
                try
                {
                    var path = paths[0];
                    var lines = File.ReadAllLines(path, Encoding.UTF8);
                    foreach (var line in lines)
                    {
                        try
                        {
                            var msg = JsonHelper.JsonDeserialize<T>(line);
                            if (msg != null)
                            {
                                list.Add(msg);
                            }
                        }
                        catch (Exception ex)
                        {
                            Logger.Trace(ex.Message);
                        }
                    }
                    filePath = path;
                }
                catch (Exception ex)
                {
                    Logger.WarnException(ex);
                }
            }
            return list;
        }

        public void Dispose()
        {
            SaveCollection?.Dispose();
            SaveCollection = null;
            _timerClose.Dispose();
        }
    }
}
